import logging
import json

from django.conf import settings
from django.http import Http404,HttpResponseNotFound
from django.shortcuts import render
from django.views import View
from django.core.paginator import Paginator, PageNotAnInteger,EmptyPage#分页类
from haystack.views import SearchView as _SearchView
from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_page
# Create your views here.

from . import models
from . import constants #自定义常量
from utils.json_fun import to_json_data#重封装jsonrepons
from utils.res_code import Code,error_map

logger = logging.getLogger('django')

#1.index页面

@method_decorator(cache_page(timeout=120,cache='page_cache'),name='dispatch')
class IndexView(View):
    '''
    create index page view
    index页面
    '''
    def get(self,request):
        # only指定查询条件优化查询结果  defer排除   True为已删除
        tags = models.Tag.objects.only('id','name').filter(is_delete=False)
        # context = { #不够优化,使用locals()更方便
        #     'tags':tags,
        # }
        hot_news = models.HotNews.objects.select_related('news').\
            only('news__image_url','news__title','news_id').\
                       filter(is_delete=False).order_by('priority','-news__clicks')[:constants.SHOW_HOTNEWS_COUNT]

        return render(request,'news/index.html',locals()) #locals()获取local区域所有变量


# 1.创建一个新闻列表视图类
class NewsListView(View):
    '''
    create news list view
    route:/news/
    '''
    # 2.获取参数
    def get(self,request):
        try:# 3.校验参数
            tag_id = int(request.GET.get('tag_id',0))#0是最新资讯
        except Exception as e:
            logger.error('标签错误:\n{}'.format(e))
            tag_id = 0
        try:# 3.校验参数
            page = int(request.GET.get('page',1))#默认第一页
        except Exception as e:
            logger.error('当前页数错误:\n{}'.format(e))
            page = 1
        # 4.从新闻数据库查询新闻列表数据  Paginator分页
        '''需要id,标题title,摘要digest,作者author_name,更新日期update_time,分类tag_name'''
        '''
        # tag_id == 0 时则查不到 0是最新新闻
        news = models.News.objects.select_related('tag','author').\
            only('title','digest','author__username','tag__name','image_url','update_time').\
            filter(is_delete=False,tag_id=tag_id)
        '''
        news_queryset = models.News.objects.select_related('tag','author').\
            only('title','digest','author__username','tag__name','image_url','update_time')
        news = news_queryset.filter(is_delete=False,tag_id=tag_id) or \
              news_queryset.filter(is_delete=False)

        paginator = Paginator(news,#对象列表    #分页器
                              constants.PER_PAGE_NEWS_COUNT)   #每一页显示个数
        try:
            news_info = paginator.page(page)    #页面内容
        except EmptyPage:
            #若用户访问的页数大于实际页数,则返回最后一页数据
            logging.info("用户访问页数大于总页")  #记录日志
            news_info = paginator.page(paginator.num_pages) #返回最后一页
        # 5.序列化数据
        news_info_list = []
        for n in news_info:
            news_info_list.append({
                'id':n.id,
                'title':n.title,
                'digest':n.digest,
                'image_url':n.image_url,
                'tag_name':n.tag.name,
                'author':n.author.username,
                'update_time':n.update_time.strftime('%Y年%m月%d日 %H:%M'),
            })
        data = {
            'total_pages':paginator.num_pages,#总页数
            'news':news_info_list #
        }
        # 6.反回给前端
        return to_json_data(data=data)

#1.新闻详情视图
class NewsDetailView(View):
    '''
    create news detail view
    创建新闻详情视图
    url:/news/<int:news_id>/
    '''
    def get(self,request,news_id):
        news = models.News.objects.select_related('tag','author').only('title','content','update_time','tag__name','author__username').filter(is_delete=False,id=news_id).first()
        if news:
            comments = models.Comment.objects.select_related('author','parents').\
                only('content','author__username','update_time','parents__author__username','parents__content','parents__update_time').\
                    filter(is_delete=False,news_id=news_id)

            comments_list = []
            for comm in comments:
                #卸载models中的序列化操作
                comments_list.append(comm.to_dict_data())
            news.clicks += 1
            news.save(update_fields=['clicks'])
            return render(request,'news/news_detail.html', locals())
        else:
            raise Http404("<新闻{}不存在>".format(news_id))

#1.创建一个轮播图视图类
class NewsBanner(View):
    '''
    create news banner view
    url:/news/banners/
    '''
    #2.获取数据(数据库中数据)
    def get(self,request):
        banners = models.Banner.objects.select_related('news').\
            only('image_url','news_id','news__title').\
                  filter(is_delete=False)[:constants.SHOW_BANNER_COUNT]
        #3.序列化输出
        banners_info_list = []
        for b in banners:
            banners_info_list.append({
                'image_url': b.image_url,
                'news_id': b.news.id,
                'news_title': b.news.title,
            })

            # 创建返回给前端的数据
        data = {
            'banners': banners_info_list
        }

        return to_json_data(data=data)


#1.新闻评论视图
class NewsCommentView(View):
    """
    creat news commens View
    url:/news/<int:news_id>/comments/
    """
    #2.获取前端参数
    def post(self,request,news_id):
        if not request.user.is_authenticated:#判断用户是否登录
            return to_json_data(errno=Code.SESSIONERR, errmsg=error_map[Code.SESSIONERR])
        if not models.News.objects.only("id").filter(is_delete=False,id=news_id).exists():
            return to_json_data(errno=Code.PARAMERR, errmsg=error_map[Code.PARAMERR])
        try:
            json_data = request.body
            # to_dict_data = json.loads(josn_data.decode('utf8')) if josn_data else None
            if not json_data:
                return to_json_data(errno=Code.PARAMERR, errmsg="参数为空,请重新输入")
            dict_data = json.loads(json_data.decode('utf8'))
        except Exception as e:
            logger.info('错误信息:\n{}'.format(e))
            return to_json_data(errno=Code.UNKOWNERR, errmsg=error_map[Code.UNKOWNERR])

        content = dict_data.get('content')
        parent_id = dict_data.get('parent_id')
        # 3.校验参数
        if not content: #校验评论不为空
            return to_json_data(errno=Code.PARAMERR, errmsg="评论内容为空")
        try:    #校验parent_id为整数
            if parent_id: #如果是""是false
                parent_id = int(parent_id)
                if not models.Comment.objects.only("id").\
                        filter(is_delete=False,id=parent_id,news_id=news_id).exists():#如果查不到数据
                    return to_json_data(errno=Code.PARAMERR, errmsg=error_map[Code.PARAMERR])
        except Exception as e:
            logger.info("前端传如的parent_id异常:\n{}".format(e))
            return to_json_data(errno=Code.PARAMERR, errmsg=error_map[Code.UNKOWNERR])
        #4.保存评论
        news_comment = models.Comment()
        news_comment.content = content
        news_comment.news_id = news_id
        news_comment.parents_id = parent_id if parent_id else None#防止传空 ""
        news_comment.author = request.user #获取用户信息
        news_comment.is_delete = 0
        news_comment.save()

        return to_json_data(errno="0", errmsg= None,data=news_comment.to_dict_data())#to_dict_data模型中的序列化操作

    # 知识点:测试用例


#1.搜索视图
class SearchView(_SearchView):
    # 模版文件
    template = 'news/search.html'

    # 重写响应方式，如果请求参数q为空，返回模型News的热门新闻数据，否则根据参数q搜索相关数据
    def create_response(self):
        kw = self.request.GET.get('q', '')
        if not kw:
            show_all = True
            hot_news = models.HotNews.objects.select_related('news'). \
                only('news__title', 'news__image_url', 'news__id'). \
                filter(is_delete=False).order_by('priority', '-news__clicks')

            paginator = Paginator(hot_news, settings.HAYSTACK_SEARCH_RESULTS_PER_PAGE)#分页
            try:
                page = paginator.page(int(self.request.GET.get('page', 1)))
            except PageNotAnInteger:
                # 如果参数page的数据类型不是整型，则返回第一页数据
                page = paginator.page(1)
            except EmptyPage:
                # 用户访问的页数大于实际页数，则返回最后一页的数据
                page = paginator.page(paginator.num_pages)
            return render(self.request, self.template, locals())
        else:
            show_all = False
            qs = super(SearchView, self).create_response()
            print(qs)
            return qs
